/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.annotation;

import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.util.function.Supplier;

/**
 * 用于以编程方式注册 bean 类的便捷适配器。
 * 作用：
 * 1、读取 spring 内部的初始的 beanFactoryPostProcess 和 其他的几种 beanPostProcess。
 * 2、提供程序员注册 BeanDefinition，主要是加了 @Configuration 的类。
 *
 * 读取方式：
 * 1、spring内部：AnnotatedBeanDefinitionReader主要读取 spring 内部的 BeanDefinition
 * 	  这里主要是注册内部的 BeanDefinition，比如唯一的 beanFactoryPostProcess 的实现类 ConfigurationClassPostProcessor 和 其他的几种 beanPostProcess。
 * 2、程序员调用：他也提供了一个可以让程序员自己注册 BeanDefinition 到容器的接口，register()
 *
 *
 * <p>这是 {@link ClassPathBeanDefinitionScanner} 的替代方案，应用相同的注释分辨率，但仅适用于显式注册的类。
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @author Sam Brannen
 * @author Phillip Webb
 * @since 3.0
 * @see AnnotationConfigApplicationContext#register
 */
public class AnnotatedBeanDefinitionReader {

	// 用于注册和管理 bean 定义对象
	private final BeanDefinitionRegistry registry;

	// 用于注册 Bean 时生成 beanName
	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

	// 类作用域解析器（根据 AnnotatedGenericBeanDefinition 解析类作用域）
	// 用于解析 @Scope 注解，默认使用 AnnotationScopeMetadataResolver 类
	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

	// 用于解析 @Conditional 注解。
	private ConditionEvaluator conditionEvaluator;


	/**
	 * 为给定的注册表创建一个新的 {@code AnnotatedBeanDefinitionReader}。
	 * 这里的 BeanDefinitionRegistry registry 是通过在 AnnotationConfigApplicationContext 的构造方法中传进来的 this
	 * 所以说明 AnnotationConfigApplicationContext 实现了 BeanDefinitionRegistry
	 *
	 * AnnotationConfigApplicationContext extends GenericApplicationContext（通用上下文）
	 * GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry
	 *
	 * <p>如果注册表是 {@link EnvironmentCapable}，例如是 {@code ApplicationContext}，
	 * {@link Environment} 将被继承，否则将创建并使用新的 {@link StandardEnvironment}。
	 * @param registry {@code BeanFactory} 以 {@code BeanDefinitionRegistry} 的形式加载 bean 定义
	 *
	 * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
	 * @see #setEnvironment(Environment)
	 */
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
	}

	/**
	 * 使用给定的 {@link Environment} 为给定的注册表创建一个新的 {@code AnnotatedBeanDefinitionReader}。
	 *
	 * @param registry {@code BeanFactory} 以 {@code BeanDefinitionRegistry} 的形式加载 bean 定义
	 * @param environment 在评估 bean 定义配置文件时使用的 {@code Environment}。
	 * @since 3.1
	 */
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;

		// ConditionEvaluator 完成条件注解的判断，在后面的 Spring Boot 中有大量的应用
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		// 这句会把一些自动注解处理器加入到 ApplicationContext 下的 BeanFactory 的 BeanDefinitions 中，
		// 也就是 Spring 中 Bean 的管理完全交给了 ApplicationContext
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}


	/**
	 * Get the BeanDefinitionRegistry that this reader operates on.
	 */
	public final BeanDefinitionRegistry getRegistry() {
		return this.registry;
	}

	/**
	 * Set the {@code Environment} to use when evaluating whether
	 * {@link Conditional @Conditional}-annotated component classes should be registered.
	 * <p>The default is a {@link StandardEnvironment}.
	 * @see #registerBean(Class, String, Class...)
	 */
	public void setEnvironment(Environment environment) {
		this.conditionEvaluator = new ConditionEvaluator(this.registry, environment, null);
	}

	/**
	 * Set the {@code BeanNameGenerator} to use for detected bean classes.
	 * <p>The default is a {@link AnnotationBeanNameGenerator}.
	 */
	public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
		this.beanNameGenerator =
				(beanNameGenerator != null ? beanNameGenerator : AnnotationBeanNameGenerator.INSTANCE);
	}

	/**
	 * Set the {@code ScopeMetadataResolver} to use for registered component classes.
	 * <p>The default is an {@link AnnotationScopeMetadataResolver}.
	 */
	public void setScopeMetadataResolver(@Nullable ScopeMetadataResolver scopeMetadataResolver) {
		this.scopeMetadataResolver =
				(scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
	}


	/**
	 * Register one or more component classes to be processed.
	 * <p>Calls to {@code register} are idempotent; adding the same
	 * component class more than once has no additional effect.
	 * @param componentClasses one or more component classes,
	 * e.g. {@link Configuration @Configuration} classes
	 */
	public void register(Class<?>... componentClasses) {
		for (Class<?> componentClass : componentClasses) {
			registerBean(componentClass);
		}
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations.
	 * @param beanClass the class of the bean
	 */
	public void registerBean(Class<?> beanClass) {
		doRegisterBean(beanClass, null, null, null, null);
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations.
	 * @param beanClass the class of the bean
	 * @param name an explicit name for the bean
	 * (or {@code null} for generating a default bean name)
	 * @since 5.2
	 */
	public void registerBean(Class<?> beanClass, @Nullable String name) {
		doRegisterBean(beanClass, name, null, null, null);
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations.
	 * @param beanClass the class of the bean
	 * @param qualifiers specific qualifier annotations to consider,
	 * in addition to qualifiers at the bean class level
	 */
	@SuppressWarnings("unchecked")
	public void registerBean(Class<?> beanClass, Class<? extends Annotation>... qualifiers) {
		doRegisterBean(beanClass, null, qualifiers, null, null);
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations.
	 * @param beanClass the class of the bean
	 * @param name an explicit name for the bean
	 * (or {@code null} for generating a default bean name)
	 * @param qualifiers specific qualifier annotations to consider,
	 * in addition to qualifiers at the bean class level
	 */
	@SuppressWarnings("unchecked")
	public void registerBean(Class<?> beanClass, @Nullable String name,
			Class<? extends Annotation>... qualifiers) {

		doRegisterBean(beanClass, name, qualifiers, null, null);
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations, using the given supplier for obtaining a new
	 * instance (possibly declared as a lambda expression or method reference).
	 * @param beanClass the class of the bean
	 * @param supplier a callback for creating an instance of the bean
	 * (may be {@code null})
	 * @since 5.0
	 */
	public <T> void registerBean(Class<T> beanClass, @Nullable Supplier<T> supplier) {
		doRegisterBean(beanClass, null, null, supplier, null);
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations, using the given supplier for obtaining a new
	 * instance (possibly declared as a lambda expression or method reference).
	 * @param beanClass the class of the bean
	 * @param name an explicit name for the bean
	 * (or {@code null} for generating a default bean name)
	 * @param supplier a callback for creating an instance of the bean
	 * (may be {@code null})
	 * @since 5.0
	 */
	public <T> void registerBean(Class<T> beanClass, @Nullable String name, @Nullable Supplier<T> supplier) {
		doRegisterBean(beanClass, name, null, supplier, null);
	}

	/**
	 * Register a bean from the given bean class, deriving its metadata from
	 * class-declared annotations.
	 * @param beanClass the class of the bean
	 * @param name an explicit name for the bean
	 * (or {@code null} for generating a default bean name)
	 * @param supplier a callback for creating an instance of the bean
	 * (may be {@code null})
	 * @param customizers one or more callbacks for customizing the factory's
	 * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
	 * @since 5.2
	 */
	public <T> void registerBean(Class<T> beanClass, @Nullable String name, @Nullable Supplier<T> supplier,
			BeanDefinitionCustomizer... customizers) {

		doRegisterBean(beanClass, name, null, supplier, customizers);
	}

	/**
	 * 将带有注解的类转换为 BeanDefinition
	 *
	 * 参考文章：https://www.yuque.com/zuiguangyin-btxpt/kb/wto8l7w13x5i7ddy#AonWA
	 */
	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		// 【1】创建 AnnotatedGenericBeanDefinition
		// 根据指定的 Bean 创建一个 AnnotatedGenericBeanDefinition
		// 它负责将带有注解的类转换为 Spring 可以处理的 Bean 定义对象。
		// （如 @Component、@Service、@Repository 等）来定义的 Bean 类，将这些类的相关信息封装成 Bean 定义，以便后续使用。
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

		// 【2】处理条件注解（@Conditional）
		// 检查类是否满足 @Conditional 注解定义的条件，如果不满足则跳过注册。
		// 关键操作：
		// 		● 使用 ConditionEvaluator 判断是否应跳过当前 Bean 的注册。
		// 		● ConditionEvaluator 会解析 @Conditional 注解中的条件类，并调用其 matches 方法。
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		// 【3】为 Bean 定义（BeanDefinition）设置一个自定义实例生成逻辑
		// InstanceSupplier 的核心作用
		// 		● 动态控制实例化：通过 Supplier 接口定义 Bean 实例的生成逻辑，允许开发者绕过 Spring 默认的反射实例化流程，直接指定实例的创建方式。
		// 		● 支持复杂初始化场景，例如：需要手动调用构造方法、依赖特定参数、或结合第三方框架（如 Lombok、MapStruct）生成实例。
		//  典型的使用场景：延迟加载、根据运行时环境动态决定是否创建实例等
		abd.setInstanceSupplier(supplier);

		// 【4】解析作用域（@Scope）
		// 确定 Bean 的作用域（如 singleton、prototype），并将其设置到 BeanDefinition 中。
		// 关键操作：
		// 		● 默认作用域是 singleton。
		// 		● 使用 ScopeMetadataResolver（默认实现是 AnnotationScopeMetadataResolver）解析 @Scope 注解。
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		// 将类的作用域添加到数据结构
		abd.setScope(scopeMetadata.getScopeName());

		// 【5】处理通用注解（@Lazy、@Primary、@DependsOn 等）
		// 解析类上的通用注解，并将信息写入 AnnotatedGenericBeanDefinition。
		// 关键操作：
		// 	● 调用 AnnotationConfigUtils.processCommonDefinitionAnnotations() 方法，处理以下注解：
		// 	  ○ @Lazy：设置懒加载（setLazyInit）。
		// 	  ○ @Primary：标记为首选 Bean（setPrimary）。
		// 	  ○ @DependsOn：设置依赖的 Bean（setDependsOn）。
		// 	  ○ @Role：设置 Bean 的角色（如框架内部使用或用户定义）。
		// 	  ○ @Description：设置 Bean 的描述信息。
		// 处理完之后，processCommonDefinitionAnnotations 依然是将它添加到数据结构中
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

		// 【6】处理限定符（@Qualifier 或自定义注解）
		// 如果传入了额外的限定符注解（如 @Qualifier），将其添加到 BeanDefinition 中。
		// 关键操作：
		// 	 ● 支持通过 @Primary 和 @Lazy 直接标记。
		// 	 ● 其他限定符（如自定义注解）会添加到 BeanDefinition 的 qualifiers 列表中。
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}

		// 【7】生成 Bean 名称
		// 如果没有显式指定 Bean 名称，则通过 BeanNameGenerator 生成默认名称。
		// 关键操作：
		// 	● 默认使用 AnnotationBeanNameGenerator，生成规则为类名的首字母小写形式（如 userService）。
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		// 【8】处理作用域代理（Scoped Proxy）
		// 如果作用域需要代理（如 @Scope(proxyMode = ...)），创建代理对象并包装 BeanDefinition。
		// 关键操作：
		// 	● 使用 ScopedProxyUtils.createScopedProxy() 生成代理的 BeanDefinition。
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

		// 【9】注册 BeanDefinition
		// 将 definitionHolder 的结构注册给 this.registry，也就是 AnnotationConfigApplicationContext
		// AnnotationConfigApplicationContext 在初始化的时候通过调用父类的方法初始化了 DefaultListableBeanFactory
		// registerBeanDefinition 就是把 definitionHolder 这个数据结构包含的信息注册到 DefaultListableBeanFactory 这个工厂（里面的 bdm）
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}


	/**
	 * Get the Environment from the given registry if possible, otherwise return a new
	 * StandardEnvironment.
	 */
	private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		if (registry instanceof EnvironmentCapable) {
			return ((EnvironmentCapable) registry).getEnvironment();
		}
		return new StandardEnvironment();
	}

}
